#include <stdlib.h>
#include "list.h"



struct list_iterator_t list_get_iterator(struct list_t* head)
{
	struct list_iterator_t tmp;
	tmp.head = tmp.curr = head;
	tmp.first = 1;
	return tmp;
}

struct list_t* list_prev(struct list_iterator_t* list_iterator)
{
	struct list_t* ret;
	if(!list_iterator->head)
		return NULL;
	if(list_iterator->curr == list_iterator->head && !list_iterator->first)
		return NULL;
	
	ret = list_iterator->curr;
	list_iterator->curr = list_iterator->curr->prev;
	list_iterator->first = 0;
	return ret;
}

struct list_t* list_next(struct list_iterator_t* list_iterator)
{
	if(!list_iterator->head)
		return NULL;
	list_iterator->curr = list_iterator->curr->next;
	if(list_iterator->curr == list_iterator->head && !list_iterator->first)
		return NULL;
	
	list_iterator->first = 0;
	return list_iterator->curr;
}

void* list_payload_prev(struct list_iterator_t* list_iterator)
{
	struct list_t* tmp = list_prev(list_iterator);
	if(tmp)
		return tmp->payload;
	return NULL;
}

void* list_payload_next(struct list_iterator_t* list_iterator)
{
	struct list_t* tmp = list_next(list_iterator);
	if(tmp)
		return tmp->payload;
	return NULL;
}

int list_add(struct list_t** head, void* payload)
{
	struct list_t* tmp = (struct list_t*)malloc(sizeof(struct list_t));
	if(!tmp)
		return -1;
	tmp->payload = payload;
	if(*head) {
		tmp->prev = *head;
		tmp->next = (*head)->next;

		tmp->next->prev = tmp;
		(*head)->next = tmp;

		*head = tmp;
	}
	else {
		tmp->next = tmp;
		tmp->prev = tmp;
		*head = tmp;
	}
	return 0;
}

void list_del(struct list_t** head, struct list_t* todel, void (*payload_free)(void*))
{
	todel->next->prev = todel->prev;
	todel->prev->next = todel->next;
	if(*head == todel) {
		if(*head == (*head)->prev)
			*head = NULL;
		else
			*head = (*head)->prev;
	}
	payload_free(todel->payload);
	free(todel);
}

void list_free(struct list_t** head, void (*payload_free)(void*))
{
	struct list_t* list;
	struct list_iterator_t list_iterator = list_get_iterator(*head);
	
	while(list = list_prev(&list_iterator)) {
		payload_free(list->payload);
		free(list);
	}
	*head = NULL;
}

